home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / upc12bs1.zip / UUCICO / suspend2.c < prev    next >
C/C++ Source or Header  |  1993-10-03  |  18KB  |  589 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    s u s p e n d 2 . c                                             */
  3. /*                                                                    */
  4. /*    suspend/resume uupoll/uucico daemon (for OS/2)                  */
  5. /*                                                                    */
  6. /*    Author: Kai Uwe Rommel                                          */
  7. /*--------------------------------------------------------------------*/
  8.  
  9. /*--------------------------------------------------------------------*/
  10. /*       Copyright (c) 1993 by Kai Uwe Rommel                         */
  11. /*--------------------------------------------------------------------*/
  12.  
  13. /*--------------------------------------------------------------------*/
  14. /*       Changes Copyright (c) 1989-1993 by Kendra Electronic         */
  15. /*       Wonderworks.                                                 */
  16. /*                                                                    */
  17. /*       All rights reserved except those explicitly granted by       */
  18. /*       the UUPC/extended license agreement.                         */
  19. /*--------------------------------------------------------------------*/
  20.  
  21. /*--------------------------------------------------------------------*/
  22. /*                          RCS Information                           */
  23. /*--------------------------------------------------------------------*/
  24.  
  25. /*
  26.  *    $Id: suspend2.c 1.4 1993/10/03 20:37:34 ahd Exp $
  27.  *
  28.  *    Revision history:
  29.  *    $Log: suspend2.c $
  30.  * Revision 1.4  1993/10/03  20:37:34  ahd
  31.  * Further cleanup for 32 bit environment
  32.  *
  33.  * Revision 1.3  1993/09/30  03:06:28  ahd
  34.  * Move suspend signal handler into suspend2
  35.  *
  36.  * Revision 1.2  1993/09/29  04:49:20  ahd
  37.  * Various clean up, with additional messages to user
  38.  * Use unique signal handler
  39.  *
  40.  * Revision 1.1  1993/09/27  00:45:20  ahd
  41.  * Initial revision
  42.  *
  43.  */
  44.  
  45. /*
  46.  * This modules allows suspending/resuming a running "uucico -r0"
  47.  * from another process if this other process wants to make an outgoing
  48.  * call. This can be an outgoing uucico or any other application.
  49.  * An outgoing uucico can suspend the background one itself while
  50.  * other applications such as terminal emulators will require to
  51.  * be wrapped in a batch files with calls to the uuport utility.
  52.  *
  53.  * The communication between the uuport or outgoing uucico and the
  54.  * background uucico is done via a named pipe. This has the advantage
  55.  * that it also works across a network between two machines if the
  56.  * background uucico runs on a LAN server which makes the modem shareable
  57.  * to other OS/2 machines. Then another machine first suspends the uucico
  58.  * on the server using a named pipe over the network and then requests
  59.  * the modem with a "NET USE" or equivalent operation. After using and
  60.  * disconnecting from the server's modem, it can resume the uucico on
  61.  * the server, again via network pipe.
  62.  */
  63.  
  64. /*--------------------------------------------------------------------*/
  65. /*       Note that the 32 bit API doesn't handle signals like it's    */
  66. /*       16 bit older cousin.  For now, we support the client of      */
  67. /*       the of the pipe to suspend a 16 bit UUCICO, but a 32 bit     */
  68. /*       UUCICO cannot be suspended.                                  */
  69. /*--------------------------------------------------------------------*/
  70.  
  71. /*--------------------------------------------------------------------*/
  72. /*                        System include files                        */
  73. /*--------------------------------------------------------------------*/
  74.  
  75. #include <stdio.h>
  76. #include <stdlib.h>
  77. #include <string.h>
  78. #include <sys/types.h>
  79. #include <limits.h>
  80. #include <signal.h>
  81. #include <process.h>
  82.  
  83. #define INCL_DOS
  84. #define INCL_DOSPROCESS
  85. #define INCL_ERRORS
  86. #define INCL_DOSSIGNALS
  87. #include <os2.h>
  88.  
  89. /*--------------------------------------------------------------------*/
  90. /*                    UUPC/extended include files                     */
  91. /*--------------------------------------------------------------------*/
  92.  
  93. #include "lib.h"
  94. #include "hostable.h"
  95. #include "security.h"
  96. #include "dcp.h"
  97. #include "dcpsys.h"
  98. #include "safeio.h"
  99. #include "modem.h"
  100. #include "catcher.h"
  101. #include "pos2err.h"
  102. #include "suspend.h"
  103. #include "usrcatch.h"
  104.  
  105. #define STACKSIZE 8192
  106.  
  107. boolean suspend_processing = FALSE;
  108.  
  109. /* This module creates a new thread. Because this thread has a stack
  110.  * segment different from the DGROUP (unlike the main thread) this
  111.  * normally requires compilation with different options. To avoid this
  112.  * (possible because the thread does not use any library routines),
  113.  * we take care not to access any local (stack) variables but only
  114.  * static global variables. There are chances that even accessing stack
  115.  * variables would work (if BP is used) but that can't be ensured.
  116.  * The same is done (to be on the safe side) for the system signal handler.
  117.  */
  118.  
  119. static HPIPE hPipe;
  120. static char nChar;
  121. static char *portName;
  122.  
  123. #ifdef __OS2__
  124.  
  125. static HEV semWait, semFree;
  126. static ULONG postCount;
  127. static ULONG nBytes;
  128.  
  129. #else
  130.  
  131. static ULONG semWait, semFree;
  132. static PFNSIGHANDLER old;
  133. static USHORT nAction;
  134. static int nBytes;
  135. typedef USHORT APIRET ;  // Define older API return type
  136.  
  137. #endif
  138.  
  139. currentfile();
  140.  
  141. #ifdef __TURBOC__
  142. #pragma -N-
  143. #else
  144. #pragma check_stack( off )
  145. #endif
  146.  
  147. #ifndef __OS2__
  148.  
  149. /*--------------------------------------------------------------------*/
  150. /*       S u s p e n d T h r e a d                                    */
  151. /*                                                                    */
  152. /*       Accept request to release serial port                        */
  153. /*--------------------------------------------------------------------*/
  154.  
  155. static VOID FAR SuspendThread(VOID)
  156. {
  157.  
  158.  
  159. /*--------------------------------------------------------------------*/
  160. /*       Process until we get a request to change the status of       */
  161. /*       the port.                                                    */
  162. /*--------------------------------------------------------------------*/
  163.  
  164.   for (;;)
  165.   {
  166.  
  167. #ifdef __OS2__
  168.     if ( DosConnectNPipe(hPipe) )
  169.       break;
  170. #else
  171.     if ( DosConnectNmPipe(hPipe) )
  172.       break;
  173. #endif
  174.  
  175.     for (;;)
  176.     {
  177.       if ( DosRead(hPipe, &nChar, 1, &nBytes) )
  178.         break;                   // Quit if an error
  179.  
  180.       if ( nBytes == 0 )
  181.         break; /* EOF */
  182.  
  183. /*--------------------------------------------------------------------*/
  184. /*               Handle the received command character                */
  185. /*--------------------------------------------------------------------*/
  186.  
  187.       switch ( nChar )
  188.       {
  189.  
  190.         case 'Q': /* query */
  191.  
  192.           nChar = (char) (suspend_processing ? 'S' : 'R');
  193.           DosWrite(hPipe, &nChar, 1, &nBytes);
  194.  
  195.           break;
  196.  
  197.         case 'S': /* suspend */
  198.  
  199.           if ( suspend_processing ||
  200.                interactive_processing ||
  201.                terminate_processing )
  202.           {
  203.             nChar = 'E';
  204.           }
  205.           else {
  206.             suspend_processing = TRUE;
  207.  
  208. #ifdef __OS2__
  209.             raise(SIGUSR1);
  210.             nChar = (char) (DosWaitEventSem(&semFree, 20000) ? 'T' : 'O');
  211. #else
  212.             DosFlagProcess(getpid(), FLGP_PID, PFLG_A, 0);
  213.             nChar = (char) (DosSemSetWait(&semFree, 20000) ? 'T' : 'O');
  214. #endif
  215.           } /* else */
  216.  
  217.           DosWrite(hPipe, &nChar, 1, &nBytes);
  218.  
  219.           break;
  220.  
  221.         case 'R': /* release */
  222.  
  223.           if ( !suspend_processing )
  224.             nChar = 'E';
  225.           else {
  226.             suspend_processing = FALSE;
  227.  
  228. #ifdef __OS2__
  229.             DosResetEventSem( &semWait, &postCount );
  230. #else
  231.             DosSemClear(&semWait);
  232. #endif
  233.             nChar = 'O';
  234.  
  235.           } /* else */
  236.  
  237.           DosWrite(hPipe, &nChar, 1, &nBytes);
  238.  
  239.           break;
  240.  
  241.         default:
  242.  
  243.           nChar = 'U';
  244.           DosWrite(hPipe, &nChar, 1, &nBytes);
  245.  
  246.           break;
  247.  
  248.       } /* switch */
  249.  
  250.     } /* for (;;) */
  251.  
  252. /*--------------------------------------------------------------------*/
  253. /*         Drop the connection now we're done with this client.       */
  254. /*--------------------------------------------------------------------*/
  255.  
  256. #ifdef __OS2__
  257.     DosDisConnectNPipe(hPipe);
  258. #else
  259.     DosDisConnectNmPipe(hPipe);
  260. #endif
  261.  
  262.   } /* for (;;) */
  263.  
  264.   DosExit(EXIT_THREAD, 0);
  265.  
  266. } /* SuspendThread */
  267.  
  268. /*--------------------------------------------------------------------*/
  269. /*       S u s p e n d H a n d l e r                                  */
  270. /*                                                                    */
  271. /*       Signal handler for suspend hander                            */
  272. /*--------------------------------------------------------------------*/
  273.  
  274. static VOID FAR PASCAL SuspendHandler(USHORT nArg, USHORT nSig)
  275. {
  276.  
  277.   DosSetSigHandler(SuspendHandler, &old, &nAction,
  278.                    SIGA_ACKNOWLEDGE, SIG_PFLG_A);
  279.   raise(SIGUSR2);
  280.  
  281. } /* SuspendHandler */
  282.  
  283. #endif
  284.  
  285. #ifdef __TURBOC__
  286. #pragma -N
  287. #else
  288. #pragma check_stack( )
  289. #endif
  290.  
  291. /*--------------------------------------------------------------------*/
  292. /*       s u s p e n d _ i n i t                                      */
  293. /*                                                                    */
  294. /*       Initialize thread to handle port suspension                  */
  295. /*--------------------------------------------------------------------*/
  296.  
  297. void suspend_init(const char *port )
  298. {
  299.  
  300. #ifndef __OS2__
  301.  
  302.   char szPipe[FILENAME_MAX];
  303.   SEL selStack;
  304.   PSZ pStack;
  305.   TID tid;
  306.   APIRET rc;
  307.  
  308. /*--------------------------------------------------------------------*/
  309. /*      Set up the handler for signals from our suspend monitor       */
  310. /*--------------------------------------------------------------------*/
  311.  
  312.   rc = DosSetSigHandler(SuspendHandler,
  313.                         &old,
  314.                         &nAction,
  315.                         SIGA_ACCEPT,
  316.                         SIG_PFLG_A);
  317.  
  318.   if (rc)
  319.   {
  320.     printOS2error( "DosSetSigHandler", rc);
  321.     return;
  322.   }
  323.  
  324. /*--------------------------------------------------------------------*/
  325. /*                Set up the pipe name to listen upon                 */
  326. /*--------------------------------------------------------------------*/
  327.  
  328.   strcpy(szPipe, SUSPEND_PIPE);
  329.   portName =  newstr( port );    // Save for later reference
  330.   strcat(szPipe, port );
  331.  
  332.   printmsg(4,"Creating locking pipe %s", szPipe );
  333.  
  334. #ifdef __OS2__
  335.   rc = DosCreateNPipe( szPipe,
  336.                      &hPipe,
  337.                      NP_ACCESS_DUPLEX | NP_NOINHERIT | NP_NOWRITEBEHIND,
  338.                      NP_WAIT | NP_READMODE_BYTE | NP_TYPE_BYTE | 1,
  339.                      32,
  340.                      32,
  341.                      5000);
  342.  
  343.   if (rc)
  344.   {
  345.     printOS2error( "DosCreateNPipe", rc);
  346.     return;
  347.   }
  348.  
  349. #else
  350.   rc = DosMakeNmPipe(szPipe,
  351.                      &hPipe,
  352.                      NP_ACCESS_DUPLEX | NP_NOINHERIT | NP_NOWRITEBEHIND,
  353.                      NP_WAIT | NP_READMODE_BYTE | NP_TYPE_BYTE | 1,
  354.                      32,
  355.                      32,
  356.                      5000);
  357.  
  358.   if (rc)
  359.   {
  360.     printOS2error( "DosMakeNmPipe", rc);
  361.     return;
  362.   }
  363. #endif
  364.  
  365. /*--------------------------------------------------------------------*/
  366. /*       Now allocate memory for the monitor thread which will        */
  367. /*       notify us if some program wants our port.                    */
  368. /*--------------------------------------------------------------------*/
  369.  
  370. #ifdef __OS2__
  371.   pStack = malloc( STACKSIZE );
  372. #else
  373.   rc = DosAllocSeg(STACKSIZE, &selStack, SEG_NONSHARED);
  374.  
  375.   if (rc)
  376.   {
  377.     printOS2error( "DosAllocSeg", rc);
  378.     return;
  379.   }
  380.  
  381.   pStack = (PSZ) MAKEP(selStack, 0) + STACKSIZE -2 ;
  382. #endif
  383.  
  384. /*--------------------------------------------------------------------*/
  385. /*                    Now fire off the monitor thread                 */
  386. /*--------------------------------------------------------------------*/
  387.  
  388.   rc = DosCreateThread(SuspendThread, &tid, pStack);
  389.  
  390.   if (rc)
  391.   {
  392.     printOS2error( "DosCreateThread", rc);
  393.     return;
  394.   }
  395.  
  396. /*--------------------------------------------------------------------*/
  397. /*                    Finally, our signal handler                     */
  398. /*--------------------------------------------------------------------*/
  399.  
  400.   if ( signal( SIGUSR2, usrhandler ) == SIG_ERR )
  401.   {
  402.       printmsg( 0, "Couldn't set SIGUSR2\n" );
  403.       panic();
  404.   }
  405.  
  406. #endif
  407.  
  408. } /* suspend_init */
  409.  
  410. /*--------------------------------------------------------------------*/
  411. /*       s u s p e n d _ o t h e r                                    */
  412. /*                                                                    */
  413. /*       Request another UUCICO give up a modem                       */
  414. /*--------------------------------------------------------------------*/
  415.  
  416. int suspend_other(const boolean suspend,
  417.                   const char *port )
  418. {
  419.   char szPipe[FILENAME_MAX];
  420.   HFILE hPipe;
  421. #ifdef __OS2__
  422.   ULONG nAction, nBytes;
  423. #else
  424.   USHORT nAction, nBytes;
  425. #endif
  426.   UCHAR nChar;
  427.   APIRET rc = 1;
  428.   boolean firstPass = TRUE;
  429.   int result;
  430.  
  431.   strcpy(szPipe, SUSPEND_PIPE);
  432.   strcat(szPipe, port );
  433.  
  434. /*--------------------------------------------------------------------*/
  435. /*           Try to open the pipe, with one retry if needed           */
  436. /*--------------------------------------------------------------------*/
  437.  
  438.   while(rc)
  439.   {
  440.       rc = DosOpen((PSZ) szPipe,
  441.                    &hPipe,
  442.                    &nAction,
  443.                    0L,
  444.                    0,
  445.                    FILE_OPEN,
  446.                    OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE,
  447.                    0);
  448.  
  449.       if (rc)
  450.       {
  451.         if ( debuglevel >= 4 )          // No error if no passive UUCICO
  452.            printOS2error( "DosOpen", rc); // So this is only for info
  453.  
  454.         if ((rc == ERROR_PIPE_BUSY) && firstPass )
  455.         {
  456.            firstPass = FALSE;
  457.  
  458. #ifdef __OS2__
  459.            rc = DosWaitNPipe( szPipe, 5000 ); // Wait up to 5 sec for pipe
  460.            if (rc)
  461.            {
  462.              printOS2error( "DosWaitNPipe", rc);
  463.              return 0;
  464.            } /* if (rc) */
  465. #else
  466.            rc = DosWaitNmPipe( szPipe, 5000 ); // Wait up to 5 sec for pipe
  467.            if (rc)
  468.            {
  469.              printOS2error( "DosWaitNmPipe", rc);
  470.              return 0;
  471.            } /* if (rc) */
  472. #endif
  473.  
  474.         } /* if */
  475.         else
  476.            return 0;
  477.  
  478.       } /* if */
  479.  
  480.    } /* while(rc) */
  481.  
  482. /*--------------------------------------------------------------------*/
  483. /*       We have an open connect, write the request to the server     */
  484. /*       running as part of the passive UUCICO.                       */
  485. /*--------------------------------------------------------------------*/
  486.  
  487.    rc = DosWrite(hPipe, suspend ? "S" : "R", 1, &nBytes);
  488.    if (rc)
  489.    {
  490.      printOS2error( "DosWrite", rc);
  491.      DosClose(hPipe);
  492.      return -1;
  493.    }
  494.  
  495.    if ( nBytes != 1 )
  496.    {
  497.      DosClose(hPipe);
  498.      return -1;
  499.    }
  500.  
  501.    printmsg(2, "Waiting for background uucico to %s use of %s ...",
  502.                suspend ? "suspend" : "resume",
  503.                port);
  504.  
  505. /*--------------------------------------------------------------------*/
  506. /*                      Process the server response                   */
  507. /*--------------------------------------------------------------------*/
  508.  
  509.    rc = DosRead(hPipe, &nChar, 1, &nBytes);
  510.  
  511.    if (rc)
  512.    {
  513.      printOS2error( "DosRead", rc);
  514.      result = -1;
  515.    }
  516.    else if ( nBytes != 1 )
  517.    {
  518.      printmsg(0,"suspend_other: Error: No data from remote UUCICO");
  519.      result = -2;
  520.    }
  521.    else if ( nChar != 'O' )
  522.    {
  523.      printmsg(0, "Cannot %s background uucico.  Result code was %c",
  524.                  suspend ? "suspend" : "resume",
  525.                  nChar );
  526.      result = -3;
  527.    }
  528.    else
  529.       result = 1;                   // Success!
  530.  
  531. /*--------------------------------------------------------------------*/
  532. /*                     Close up and return to caller                  */
  533. /*--------------------------------------------------------------------*/
  534.  
  535.   DosClose(hPipe);
  536.  
  537.   return result;
  538.  
  539. } /* suspend_other */
  540.  
  541. /*--------------------------------------------------------------------*/
  542. /*       s u s p e n d _ w a i t                                      */
  543. /*                                                                    */
  544. /*       Wait to take the serial port back                            */
  545. /*--------------------------------------------------------------------*/
  546.  
  547. CONN_STATE suspend_wait(void)
  548. {
  549.  
  550. #ifdef __OS2__
  551.    return CONN_INITIALIZE;
  552. #else
  553.  
  554.    APIRET rc;
  555.  
  556.    printmsg(0,"suspend_wait: Port %s released, program sleeping",
  557.                portName );
  558.  
  559. #ifdef __OS2__
  560.    rc = DosResetEventSem( &semFree, &postCount);
  561.    if (rc)
  562.       printOS2error( "DosResetEventSem", rc);
  563.  
  564.    rc = DosWaitEventSem(&semWait, SEM_INDEFINITE_WAIT);
  565.    if (rc)
  566.       printOS2error( "DosWaitEventSem", rc);
  567.  
  568. #else
  569.  
  570.    rc = DosSemClear(&semFree);
  571.  
  572.    if (rc)
  573.       printOS2error( "DosSemClear", rc);
  574.  
  575.    rc = DosSemSetWait(&semWait, SEM_INDEFINITE_WAIT);
  576.    if (rc)
  577.       printOS2error( "DosSemSetWait", rc);
  578.  
  579. #endif
  580.  
  581.    if (rc)
  582.       return CONN_EXIT;
  583.    else
  584.       return CONN_INITIALIZE;
  585.  
  586. #endif
  587.  
  588. } /* suspend_wait */
  589.